
class Desire {
  constructor(targetDom) {
    this.targetDom = targetDom;
  }

  static setAnimation(dom, animation) {
    if (dom.style.animation) {
      animation = dom.style.animation + ', ' + animation;
    }
    dom.style.animation = '';
    dom.style.animation = animation;
  }

  pipe(...args) {
    // if (dom.style.animation.includes(name)) return;
    // if (document.getAnimations().find(v => v.animationName === name)) return;
    const maxTime = args.reduce((pre, fn) => {
      return Math.max(pre, fn.animation.time);
    }, 0);
    // 因为不仅仅支持0和100，所以要进行插值; 时间更短的动画要按比例换算步数
    const allSteps = args.reduce((pre, fn) => { // 以最长时间为准，获得最大摊开步数
      Object.keys(fn.keyFrames)
        .map(step => Number(step * fn.animation.time / maxTime).toFixed(2))
        .forEach(step => pre.add(step));
      return pre;
    }, new Set());
    args = args.map(fn => { // 每个动画扩展自身
      const originSteps = Object.keys(fn.keyFrames);
      const transferSteps = originSteps
        .map(step => Number(step * fn.animation.time / maxTime).toFixed(2));

      transferSteps.forEach((step, i) => {
        const originStepObj = fn.keyFrames[originSteps[i]];
        delete fn.keyFrames[originSteps[i]];
        const lastStep = i === 0 ? 0 : transferSteps[i - 1];
        const toCalcSteps = [...allSteps].filter(v => lastStep < v <= step); // 每一步都需要补全中间状态
        toCalcSteps.forEach(calcStep => {
          const calcStepObj = Desire.getCalcStepObj(originStepObj, (calcStep - lastStep) / (step - lastStep));
          fn.keyFrames[calcStep] = calcStepObj;
        });

        if (i === transferSteps.length - 1) {
          // 补全所有后续状态
          const toPatchSteps = [...allSteps].filter(v => step < v);
          toPatchSteps.forEach(patchStep => {
            fn.keyFrames[patchStep] = originStepObj;
          });
        }
      });
    })
    const result = args.reduce((pre, fn) => { // 最终合并成一个动画
      const { animation: { name }, keyFrames: _keyFrames } = fn;
      pre.name += (pre.name && '_') + name;
      Object.keys(_keyFrames).forEach(step => {
        if (step in pre.keyFrames) {
          const stepObj = pre.keyFrames[step];
          Object.keys(_keyFrames[step]).forEach(css => {
            if (css === 'transform') {
              // transform拼接
              stepObj[css] = (stepObj[css] ?? '') + ' ' + _keyFrames[step][css];
            } else {
              // 非transform 不覆盖
              stepObj[css] = stepObj[css] ?? _keyFrames[step][css];
            }
          });
        } else {
          pre.keyFrames[step] = _keyFrames[step];
        }
      });
      return pre;
    }, { name: '', keyFrames: {} });

    // const originAnimation = this.targetDom.style.animation;
    Desire.setAnimation(this.targetDom, `${result.name} ${maxTime / 1000}s`);
    const cartoon = document.createElement('style');
    document.body.appendChild(cartoon);
    const keyFrames = `
        @keyframes ${result.name} {
          ${Object.keys(result.keyFrames).map(step => {
            const stepObj = result.keyFrames[step];
            return `${step}% { ${Object.keys(stepObj).map(css => `${css}: ${stepObj[css]};`).join(' ')} }`;
          }).join(' ')}
          }
        `;
    cartoon.append(keyFrames);
    setTimeout(() => {
      // cartoon.remove();
      // this.targetDom.style.animation = originAnimation;
    }, 15_000);
  }

  static evolution(config = [10_000]) {
    const name = 'evolution';
    const [time] = config;
    const animation = { name, time };
    const keyFrames = {
      0: {
        transform: {
          rotateY: 0,
          rotateX: 0,
          rotateZ: 0
        }
      },
      100: {
        transform: {
          rotateY: 18000,
          rotateX: 360,
          rotateZ: 360
        }
      }
    }
    return { animation, keyFrames };
  }

  static flyTo(config) {
    const name = 'flyTo';
    const [me, moon, time = 3000] = config;
    // const animation = `${name} ${time / 1000}s cubic-bezier(.5, .2, 1, .2)`;
    const { left: selfLeft, top: selfTop } = me.getBoundingClientRect();
    const { left, top } = moon.getBoundingClientRect();
    const x = left - selfLeft;
    const y = top - selfTop;
    const animation = { name, time };
    const keyFrames = {
      0: {
        transform: {
          translateX: 0,
          translateY: 0
        }
      },
      100: {
        transform: {
          translateX: x,
          translateY: y
        }
      }
    }
    return { animation, keyFrames };
  }

  static getCalcStepObj(originalStepObj, ratio) {
    ratio
    if (Object.keys(originalStepObj)[0] === 'transform') {
      // 展开一层
    }
    return {};
  }

  static getCssValue() {

  }

  static stepObjToCssStr() {

  }

}
export default Desire;
window.Desire = Desire;

Desire.boom = function boom(dom, config = [6, 50, 10_000]) {
  if (dom.style.animation) return;
  const [frequency, width, time] = config;
  const step = 10 - frequency;
  const repeat = time / 1000 / 10;
  Desire.setAnimation(dom, `boom 10s linear  0s ${repeat}`)
  let sum = 0;
  let direction = 1;
  let str = "@keyframes boom { 0% {transform: translateX(0px) }";
  while (sum < 100) {
    if (sum === 0) sum += step / 2;
    else if (sum + step > 100) sum += step / 2;
    else sum += step;
    if (sum >= 100 || 100 - sum < step / 4) break;
    direction *= -1;
    const move = direction * Math.floor(width + (Math.random() * width) / 2);
    str += `
        ${sum}%{transform: translateX(${move}px)}
      `;
  }
  str += " 100% {transform: translateX(0px)} }";
  const cartoon = document.createElement("style");
  document.body.appendChild(cartoon);
  cartoon.append(str);
}